package com.mxx.common.data.jpa;

import org.springframework.data.jpa.domain.Specification;

import javax.persistence.criteria.*;

@FunctionalInterface
public interface UpdateSpecification<T> extends Specification<T> {

    Result buildUpdate(Root root, CriteriaBuilder criteriaBuilder, CriteriaQuery criteriaQuery, CriteriaUpdate criteriaUpdate);

    @Override
    default Predicate toPredicate(Root<T> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) {
        Result result = buildUpdate(root, criteriaBuilder, criteriaQuery, EmptyCriteriaUpdate.INSTANCE);
        return result.predicate;
    }

    @Override
    default UpdateSpecification<T> and(Specification<T> other) {
        return UpdateSpecificationComposition.composed(this, other, (builder, lhs, rhs) -> builder.and(lhs, rhs));
    }

    @Override
    default Specification<T> or(Specification<T> other) {
        return UpdateSpecificationComposition.composed(this, other, (builder, lhs, rhs) -> builder.or(lhs, rhs));
    }

    class Result {
        private boolean allowNullCondition;
        private Predicate predicate;
        private int updateFieldNumber;

        public Result(boolean allowNullCondition, int updateFieldNumber, Predicate predicate) {
            this.allowNullCondition = allowNullCondition;
            this.updateFieldNumber = updateFieldNumber;
            this.predicate = predicate;
        }

        public boolean isAllowNullCondition() {
            return allowNullCondition;
        }

        public Predicate getPredicate() {
            return predicate;
        }

        public int getUpdateFieldNumber() {
            return updateFieldNumber;
        }
    }
}
